package com.deepexi.adapter.common;

import com.deepexi.adapter.common.exception.HttpNon200Exception;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Base64;

/**
 *
 */
public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
    // 大量数据
    private static final int ONE_HOUR = 3600 * 1000;
    private static final int SO_TIME_OUT = 5 * ONE_HOUR;
    private static final int SO_REQUEST_TIME_OUT = 5 * ONE_HOUR;
    private static final int READ_TIME_OUT = 5 * ONE_HOUR;

    private static HttpPost buildHttpPost(String url, String bodyJson, String baseAuth) {
        HttpPost httpPost = new HttpPost(url);

        // 本级代理, 仅用于测试
        // HttpHost charlesProxy = new HttpHost("127.0.0.1", 8888, "http");

        final RequestConfig params = RequestConfig.custom()
                // .setProxy(charlesProxy)
                .setConnectTimeout(READ_TIME_OUT)
                .setConnectionRequestTimeout(SO_REQUEST_TIME_OUT)
                .setSocketTimeout(SO_TIME_OUT)
                .build();
        httpPost.setConfig(params);

        StringEntity entity = new StringEntity(bodyJson, "UTF-8");
        entity.setContentType("application/json; charset=UTF-8");
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setHeader("Accept", "application/json");
        if (null != baseAuth) {
            httpPost.setHeader("Authorization", "Basic " + baseAuth);
        }

        return httpPost;
    }

    private static void logRequest(String url, String request, String response) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ begin ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        sb.append("\nurl=").append(url);
        sb.append("\nrequest=").append(request);
        sb.append("\nresponse=").append(response);
        sb.append("\n↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ end ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
        logger.info(sb.toString());
    }

    /**
     * 发送post请求, 期望得到 string 请求体
     *
     * @param url      请求url
     * @param bodyJson 请求的body
     * @return String  http响应体的 body
     * @throws IOException 网络异常
     */
    public static String postJson4StringBody(String url, String bodyJson) throws IOException {
        CloseableHttpClient client = HttpClients.createDefault();
        try {
            CloseableHttpResponse response = client.execute(buildHttpPost(url, bodyJson, null));
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");

            if (logger.isDebugEnabled()) {
                logRequest(url, bodyJson, result);
            }

            return result;
        } catch (Exception ex) {
            logger.error("postJson error: ", ex);
            throw new IOException(ex);
        } finally {
            client.close();
        }
    }

    /**
     * 发送post请求, 期望得到 string 请求体, 使用Base authoricate
     *
     * @param url      请求url
     * @param bodyJson 请求的body
     * @param name     base授权 name
     * @param password base授权 password
     * @return String  http响应体的 body
     * @throws IOException HttpNon200Exception
     */
    public static String postJson4StringWithBaseAuth(String url, String bodyJson, String name, String password)
            throws IOException, HttpNon200Exception {
        String auth = Base64.getEncoder().encodeToString((name + ":" + password).getBytes());

        CloseableHttpClient client = HttpClients.createDefault();
        try {
            CloseableHttpResponse response = client.execute(buildHttpPost(url, bodyJson, auth));
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            int statusCode = response.getStatusLine().getStatusCode();
            if (logger.isDebugEnabled()) logger.debug("statusCode={}", statusCode);

            // 200+ 表示正常
            if (statusCode > 299) {
                String msg = "响应码=" + statusCode + "\n响应体=" + result;
                throw new HttpNon200Exception(msg);
            }

            if (logger.isDebugEnabled()) logRequest(url, bodyJson, result);
            return result;
        } catch (IOException ex) {
            logger.error("network error: ", ex);
            throw ex;
        } finally {
            client.close();
        }
    }
}
